package org.hackystat.storageservice.server;
import java.io.FileInputStream;
import java.io.IOException;
import java.util.Map;
import java.util.Properties;
import java.util.TreeMap;


public class ServerProperties {
	  
	  /** The admin email key. */
	  public static final String ADMIN_EMAIL_KEY =     "sensorbase.admin.email";
	  /** The admin password. */
	  public static final String ADMIN_PASSWORD_KEY =   "sensorbase.admin.password";
	  /** The database directory key. */
	  public static final String DB_DIR_KEY =          "sensorbase.db.dir";
	  /** The database implementation class. */
	  public static final String DB_IMPL_KEY =          "sensorbase.db.impl";
	  /** The storageservice hostname key. */
	  public static final String HOSTNAME_KEY =        "storageservice.hostname";
	  /** The storageservice context root. */
	  public static final String CONTEXT_ROOT_KEY =     "storageservice.context.root";
	  /** The logging level key. */
	  public static final String LOGGING_LEVEL_KEY =   "storageservice.logging.level";
	  /** The storageservice port key. */
	  public static final String PORT_KEY =            "storageservice.port";
	  /** The XML directory key. */
	  public static final String XML_DIR_KEY =         "storageservice.xml.dir";
	  /** The Restlet Logging key. */
	  public static final String RESTLET_LOGGING_KEY = "storageservice.restlet.logging";
	  /** Whether to compress on startup. */
	  public static final String COMPRESS_ON_STARTUP_KEY =   "sensorbase.db.startup.compress";  
	  /** Whether to re-index on startup. */
	  public static final String REINDEX_ON_STARTUP_KEY =   "sensorbase.db.startup.reindex";  
	  
	  private String falseString = "false"; // for PMD.
	 /** Where we store the properties. */
	  private Properties properties; 
	 
	  private static String FALSE = "false";
	  /**
	   * Creates a new ServerProperties instance. 
	   * Prints an error to the console if problems occur on loading. 
	   */
	  public ServerProperties() {
	    try {
	      initializeProperties();
	    }
	    catch (Exception e) {
	      System.out.println("Error initializing StorageServiceProperties properties: " + e.getMessage());
	    }
	  }
	  
	  /**
	   * Reads in the properties in ~/.hackystat/storageservice/storageservice.properties 
	   * if this file exists, and provides default values for all properties.
	   * @throws Exception if errors occur.
	   */
	  private void initializeProperties () throws Exception {
	    String userHome = System.getProperty("user.home");
	    String userDir = System.getProperty("user.dir");
	    String hackyHome = userHome + "/.hackystat";
	    String sensorBaseHome = hackyHome + "/sensorbase";
	    String propFile = userHome + "/.hackystat/storageservice/storageservice.properties";
	    this.properties = new Properties();
	    // Set defaults
	    String defaultAdmin = "admin@hackystat.org";
	    properties.setProperty(ADMIN_EMAIL_KEY, defaultAdmin);
	    properties.setProperty(ADMIN_PASSWORD_KEY, defaultAdmin);
	    properties.setProperty(HOSTNAME_KEY, "localhost");
	    properties.setProperty(PORT_KEY, "9888");
	    properties.setProperty(CONTEXT_ROOT_KEY, "storageservice");
	    properties.setProperty(DB_DIR_KEY, sensorBaseHome + "/db");
	    properties.setProperty(DB_IMPL_KEY, "org.hackystat.storageservice.db.derby.DerbyImplementation");
	    properties.setProperty(LOGGING_LEVEL_KEY, "INFO");
	    properties.setProperty(RESTLET_LOGGING_KEY, falseString);
	    properties.setProperty(XML_DIR_KEY, userDir + "/xml");
	    properties.setProperty(COMPRESS_ON_STARTUP_KEY, FALSE);
	    properties.setProperty(REINDEX_ON_STARTUP_KEY, FALSE);
	    FileInputStream stream = null;
	    try {
	      stream = new FileInputStream(propFile);
	      System.out.println("Loading storageservice properties from: " + propFile);
	      properties.load(stream);
	    }
	    catch (IOException e) {
	      System.out.println(propFile + " not found. Using default storageservice properties.");
	    }
	    finally {
	      if (stream != null) {
	        stream.close();
	      }
	    }
	    
	    trimProperties(properties);
	  }
	  
	  /**
	   * Ensures that the there is no leading or trailing whitespace in the property values.
	   * The fact that we need to do this indicates a bug in Java's Properties implementation to me. 
	   * @param properties The properties. 
	   */
	  private void trimProperties(Properties properties) {
	    // Have to do this iteration in a Java 5 compatible manner. no stringPropertyNames().
	    for (Map.Entry<Object, Object> entry : properties.entrySet()) {
	      String propName = (String)entry.getKey();
	      properties.setProperty(propName, properties.getProperty(propName).trim());
	    }
	  }

	  /**
	   * Returns a string containing all current properties in alphabetical order.
	   * @return A string with the properties.  
	   */
	  public String echoProperties() {
	    String cr = System.getProperty("line.separator"); 
	    String eq = " = ";
	    String pad = "                ";
	    // Adding them to a treemap has the effect of alphabetizing them. 
	    TreeMap<String, String> alphaProps = new TreeMap<String, String>();
	    for (Map.Entry<Object, Object> entry : this.properties.entrySet()) {
	      String propName = (String)entry.getKey();
	      String propValue = (String)entry.getValue();
	      alphaProps.put(propName, propValue);
	    }
	    StringBuffer buff = new StringBuffer(25);
	    buff.append("StorageService Properties:").append(cr);
	    for (String key : alphaProps.keySet()) {
	      buff.append(pad).append(key).append(eq).append(get(key)).append(cr);
	    }
	    return buff.toString();
	  }
	  
	  /**
	   * Returns the value of the Server Property specified by the key.
	   * @param key Should be one of the public static final strings in this class.
	   * @return The value of the key, or null if not found.
	   */
	  public String get(String key) {
	    return this.properties.getProperty(key);
	  }
	  /**
	   * True if the sensorbase.properties file indicates that the user wishes to compress the db
	   * on startup. 
	   * @return True if compress on startup.
	   */
	  public boolean compressOnStartup () {
	    return this.properties.getProperty(COMPRESS_ON_STARTUP_KEY).equalsIgnoreCase("true");
	  }
	  
	  /**
	   * True if the sensorbase.properties file indicates the user wants to reindex on startup. 
	   * @return True if reindex on startup. 
	   */
	  public boolean reindexOnStartup () {
	    return this.properties.getProperty(REINDEX_ON_STARTUP_KEY).equalsIgnoreCase("true");
	  }

}
